/*
  Copyright (c) 2008-2013  John Lee (j.y.lee@yeah.net)
  All rights reserved.

  Redistribution and use in source and binary forms, with or without
  modification, are permitted provided that the following conditions are met:

  * Redistributions of source code must retain the above copyright
    notice, this list of conditions and the following disclaimer.

  * Redistributions in binary form must reproduce the above copyright
    notice, this list of conditions and the following disclaimer in
    the documentation and/or other materials provided with the
    distribution.

  * Neither the name of the copyright holders nor the names of
    contributors may be used to endorse or promote products derived
    from this software without specific prior written permission.

  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
  AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
  IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
  ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
  LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
  CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
  SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
  INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
  CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
  ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
  POSSIBILITY OF SUCH DAMAGE.
*/

#ifndef __LIGHTWEIGHT_OBJECT_ORENTED_KERNEL_HPP
#error "Include <look.h> or <look.hpp> instead of this file."
#elif !defined(__GNUG__)
#error This header file must only be compiled by GNU C++ compiler.
#elif (__GNUC__ * 0x1000000 + __GNUC_MINOR__ * 0x10000 + __GNUC_PATCHLEVEL__ * 0x100) < 0x040702
#error GCC 4.7.2 or greater is required.
#elif !defined(__ARM_ARCH_6M__) && !defined(__ARM_ARCH_7M__)
#error This header file must only be compiled for ARMv6-M and ARMv7-M architecture.
#else

#ifndef __LOOK_INTERFACE
#define __LOOK_INTERFACE

#pragma interface

#include <cstdint>

#define __LOOK_VERSION__    0x20130310UL

#define LOOK_HWINIT()       LOOK_HWINIT_PRIORITY(5)
#define LOOK_HWINIT_PRIORITY(PRIORITY)  __LOOK_HWINIT(__COUNTER__, PRIORITY)

#if !defined(__DOXYGEN__)
#ifdef __INLINE
#undef __INLINE
#endif  // __INLINE
#define __INLINE            __attribute__((always_inline)) inline

#ifdef __WEAK
#undef __WEAK
#endif  // __WEAK
#define __WEAK              __attribute__((noinline, weak))

#ifndef __CONCAT
#define __CONCAT(a, b)      __CONCAT_I(a, b)
#define __CONCAT_I(a, b)    a ## b
#endif  // __CONCAT

#define __LOOK_HWINIT(CNT, PRIORITY)                                    \
    __attribute__((constructor(101 + PRIORITY))) static void __CONCAT(look_hwinit_, CNT)()

#define LOOK_SVC(_N, _R, _F, ...)           \
    ({                                      \
        register auto f asm ("ip") = reinterpret_cast<void (*)()>(_F);  \
        register _R result asm ("r0");      \
        __asm__ __volatile__(               \
            "svc %[n]"  "\n\t"              \
            : "=r" (result)                 \
            : [n] "i" (_N), "r" (f), ##__VA_ARGS__  \
            : "memory"                      \
        );                                  \
        result;                             \
    })

#ifdef __ARM_ARCH_6M__
#define look    look_armv6m
#else
#define look    look_armv7m
#endif  // __ARM_ARCH_6M__
#endif  // !__DOXYGEN__

namespace look {
    constexpr uint_fast32_t operator "" _msec(uint64_t msec);
    constexpr uint_fast32_t operator "" _msec(long double msec);
    constexpr uint_fast32_t operator "" _sec(uint64_t sec);
    constexpr uint_fast32_t operator "" _sec(long double sec);
    constexpr uint_fast32_t operator "" _min(uint64_t min);
    constexpr uint_fast32_t operator "" _min(long double min);
    constexpr uint_fast32_t operator "" _hour(uint64_t hour);
    constexpr uint_fast32_t operator "" _hour(long double hour);

    class sink_t {
    public:
        __INLINE sink_t();
        virtual void on_signal(void* addr, uintptr_t signal);
    };

    class interrupt_t : public sink_t {
    public:
        __INLINE interrupt_t();
        __INLINE interrupt_t* attach(uint_fast8_t irq);

    private:
        virtual bool isr(int vector) = 0;
        virtual void dsr(int vector, uint_fast16_t count) = 0;
    };

    class vector_t {
        friend class interrupt_t;
        friend class systick_t;

    public:
        __INLINE static void enable(uint_fast8_t irq);
        __INLINE static void disable(uint_fast8_t irq);
        __INLINE static void set_priority(uint_fast8_t irq, uint_fast8_t priority);

    private:
        __INLINE interrupt_t* attach(interrupt_t* intr);
        static void stack();
        static void reset();
        static void libc_reset();
        static void dsr();
        static void nmi();
        static void hard_fault();
        static void vsr();

#ifdef __ARM_ARCH_7M__
        static void mem_manage();
        static void bus_fault();
        static void usage_fault();
        static void debug_monitor();
#endif  // __ARM_ARCH_7M__

        union {
            struct {
                interrupt_t* interrupt;
                uint16_t count;
                uint8_t next;
            };
            uint64_t data;
        };

        __attribute__((aligned(4))) static vector_t table[];
        __attribute__((section(".vector"), used)) static void (*const vectors[])();
    };

    class timer_t {
    public:
        __INLINE timer_t(sink_t& sink);
        __INLINE uintptr_t start(uintptr_t interval);
        __INLINE uintptr_t kill();
        __INLINE uintptr_t do_start(uintptr_t interval);
        __INLINE uintptr_t do_kill();

    private:
        uintptr_t count;
        sink_t* sink;
        timer_t* next;
        timer_t* prev;
    };

    class systick_t : public interrupt_t {
    public:
        __INLINE systick_t(uint_fast32_t reload, uint_fast8_t priority = 0);
        __INLINE uintptr_t get_jiffies() const;
        __INLINE uintptr_t set_timer(timer_t& timer, uintptr_t interval);
        __INLINE uintptr_t kill_timer(timer_t& timer);
        uintptr_t do_set_timer(timer_t& timer, uintptr_t interval);

    protected:
        bool isr(int vector);
        void dsr(int vector, uint_fast16_t count);

    private:
        volatile uintptr_t jiffies;
        uintptr_t internal_data[8];
    };

    namespace base {
        class task_t;
    }

    class sync_t {
    public:
        __INLINE sync_t();
        __INLINE void block(uintptr_t timeout = 0);
        void do_block();

    protected:
        __INLINE base::task_t* wakeup(uintptr_t data, base::task_t* task = nullptr);
        __INLINE base::task_t* do_wakeup(uintptr_t data, base::task_t* task = nullptr);

    protected:
        uintptr_t internal_data;
    };

    class sem_t : public sync_t {
    public:
        __INLINE sem_t(uintptr_t cnt = 0);
        __INLINE uintptr_t get_count() const;

#ifdef __ARM_ARCH_6M__
        __INLINE bool trywait();
#else   // __ARM_ARCH_6M__
        bool trywait();
#endif  // __ARM_ARCH_6M__

        __INLINE bool wait(uintptr_t timeout = 0);
        __INLINE void post();

        bool do_trywait();
        bool do_post();

    private:
        uintptr_t count;
    };

    namespace base {
        class mbox_t : public sync_t {
        protected:
            __INLINE mbox_t(uint_fast8_t size);
            __INLINE uint_fast8_t get_entries() const;

            __INLINE bool tryget(uintptr_t& msg);
            __INLINE bool get(uintptr_t& msg, uintptr_t timeout = 0);
            __INLINE bool tryput(uintptr_t msg, bool front);
            __INLINE bool put(uintptr_t msg, bool front, uintptr_t timeout = 0);
            bool do_tryget(uintptr_t& msg);
            bool do_tryput(uintptr_t msg, bool front);

        protected:
            uint8_t size;
            uint8_t in;
            uint8_t out;
            uint8_t entries;
        };

        class flag_t : public sync_t {
        public:
            enum mode_t {
                ANY_KEEP,
                ANY_CONSUME,
                ALL_KEEP,
                ALL_CONSUME,
                LSB_KEEP,
                LSB_CONSUME
            };

        public:
            __INLINE uintptr_t peek() const;

#ifdef __ARM_ARCH_6M__
            __INLINE uintptr_t poll(uintptr_t pattern, mode_t mode);
            __INLINE void mask_bits(uintptr_t pattern);
#else   // __ARM_ARCH_6M__
            uintptr_t poll(uintptr_t pattern, mode_t mode);
            void mask_bits(uintptr_t pattern);
#endif  // __ARM_ARCH_6M__

            __INLINE uintptr_t wait(uintptr_t pattern, mode_t mode, uintptr_t timeout = 0);

            uintptr_t do_poll(uintptr_t pattern, mode_t mode);
            void do_mask_bits(uintptr_t pattern);

        protected:
            __INLINE flag_t(uintptr_t flags);

        protected:
            uintptr_t flags;
        };
    }

    template<typename QUEUE, typename MSG, uint8_t SIZE>
    class queue_t : public QUEUE {
    public:
        __INLINE uint_fast8_t get_size() const;
        __INLINE bool peek(MSG& msg) const;

        __INLINE bool tryget(MSG& msg);
        __INLINE bool get(MSG& msg, uintptr_t timeout = 0);
        __INLINE bool tryput(MSG msg);
        __INLINE bool tryput_front(MSG msg);
        __INLINE bool put(MSG msg, uintptr_t timeout = 0);
        __INLINE bool put_front(MSG msg, uintptr_t timeout = 0);

        __INLINE bool do_tryget(MSG& msg);
        __INLINE bool do_tryput(MSG msg);
        __INLINE bool do_tryput_front(MSG msg);

    protected:
        __INLINE queue_t();

    private:
        MSG buffer[SIZE];
    };

    template<typename MSG, uint8_t SIZE>
    class mbox_t : public queue_t<base::mbox_t, MSG, SIZE> {
        static_assert(sizeof(MSG) == sizeof(uintptr_t), "the type argument for <MSG> must be same size as uintptr_t");
        static_assert(SIZE > 0 && SIZE < 256, "<SIZE> must be greater than 0 and less than 256");

    public:
        __INLINE mbox_t();
    };

    class idle_task_t : public sink_t {
    public:
        enum {
            MIN_CONTEXT_SIZE = 16
        };

    protected:
        __INLINE idle_task_t();

    protected:
        void init(uintptr_t& context, void* routine);

    private:
        uintptr_t* context;
        uintptr_t info;
    };

    extern idle_task_t idle_task;

    namespace base {
        class task_t : public idle_task_t {
        public:
            __INLINE bool wakeup();
            bool do_wakeup();

        protected:
            __INLINE task_t();

        protected:
            void on_signal(void* addr, uintptr_t signal);
        };

        class sched_t : public sink_t {
            friend class look::vector_t;
            friend class look::sync_t;

        public:
            __INLINE void lock();
            __INLINE void unlock();
            __INLINE void unlock_reschedule();
            __INLINE void reschedule();

            void do_reschedule();
            void do_unlock_reschedule();

            __INLINE task_t& get_current_task();

        protected:
            __INLINE sched_t();
            task_t* do_wakeup(sync_t& sync, task_t* task, uintptr_t result);

        protected:
            virtual task_t* dispatch() = 0;
            virtual task_t* ready(sync_t& sync, task_t* task = nullptr) = 0;
            virtual void block(sync_t& sync) = 0;

        private:
            static void svcall();
            static void pendsv();

        protected:
            task_t* cur_task;
            uint16_t lock_count;
            uint16_t internal_data;
        };
    }

    namespace link {
        class flag_t : public base::flag_t {
        public:
            __INLINE flag_t(uintptr_t flags = 0);
            __INLINE void set_bits(uintptr_t pattern);
            void do_set_bits(uintptr_t pattern);
        };

        class task_t : public base::task_t {
        protected:
            __INLINE task_t();

        private:
            task_t* next;
            task_t* prev;
        };
    }

    extern sync_t sync;
    extern uintptr_t version;

#ifdef __ARM_ARCH_7M__
    __INLINE bool set_privilege(bool state);
    bool do_set_privilege(bool state);
#endif  // __ARM_ARCH_7M__

    __INLINE void delay(uintptr_t timeout = 0);
    __INLINE uintptr_t get_version();
}
#else   // __LOOK_INTERFACE
#ifndef __LOOK_INLINE
#define __LOOK_INLINE
constexpr uint_fast32_t look::operator "" _msec(uint64_t msec)
{
    return (msec * LOOK_TICKS_PER_SEC + 999) / 1000;
}

constexpr uint_fast32_t look::operator "" _msec(long double msec)
{
    return uint_fast32_t((msec * LOOK_TICKS_PER_SEC + 999) / 1000);
}

constexpr uint_fast32_t look::operator "" _sec(uint64_t sec)
{
    return sec * LOOK_TICKS_PER_SEC;
}

constexpr uint_fast32_t look::operator "" _sec(long double sec)
{
    return uint_fast32_t(sec * LOOK_TICKS_PER_SEC);
}

constexpr uint_fast32_t look::operator "" _min(uint64_t min)
{
    return min * LOOK_TICKS_PER_SEC * 60;
}

constexpr uint_fast32_t look::operator "" _min(long double min)
{
    return uint_fast32_t(min * LOOK_TICKS_PER_SEC * 60);
}

constexpr uint_fast32_t look::operator "" _hour(uint64_t hour)
{
    return hour * LOOK_TICKS_PER_SEC * 3600;
}

constexpr uint_fast32_t look::operator "" _hour(long double hour)
{
    return uint_fast32_t(hour * LOOK_TICKS_PER_SEC * 3600);
}

__INLINE look::sink_t::sink_t()
{
}

__INLINE look::interrupt_t::interrupt_t()
{
}

__INLINE look::interrupt_t* look::interrupt_t::attach(uint_fast8_t irq)
{
    return vector_t::table[irq - -1/*SysTick_IRQn*/].attach(this);
}

__INLINE void look::vector_t::enable(uint_fast8_t irq)
{
    reinterpret_cast<volatile uint32_t*>(0xe000e100)[irq >> 5] = 1 << (irq & 31);
}

__INLINE void look::vector_t::disable(uint_fast8_t irq)
{
    reinterpret_cast<volatile uint32_t*>(0xe000e180)[irq >> 5] = 1 << (irq & 31);
}

__INLINE look::interrupt_t* look::vector_t::attach(interrupt_t* intr)
{
    interrupt_t* old = interrupt;
    interrupt = intr;
    return old;
}

__INLINE void look::vector_t::set_priority(uint_fast8_t irq, uint_fast8_t priority)
{
    reinterpret_cast<volatile uint8_t*>(0xe000e400)[irq] = priority;
}

__INLINE look::timer_t::timer_t(sink_t& sink)
{
    this->sink = &sink;
    next = 0;
}

__INLINE uintptr_t look::timer_t::start(uintptr_t interval)
{
    return systick.set_timer(*this, interval);
}

__INLINE uintptr_t look::timer_t::kill()
{
    return start(0);
}

__INLINE uintptr_t look::timer_t::do_start(uintptr_t interval)
{
    return systick.do_set_timer(*this, interval);
}

__INLINE uintptr_t look::timer_t::do_kill()
{
    return do_start(0);
}

__INLINE look::systick_t::systick_t(uint_fast32_t reload, uint_fast8_t priority)
{
    vector_t::table[0].attach(this);
    *reinterpret_cast<volatile uint8_t*>(0xe000ed23) = priority;
    volatile uint32_t* scs = reinterpret_cast<volatile uint32_t*>(0xe000e000);
    __asm__ __volatile__("" : "+r" (scs));
    scs[6] = reload;
    scs[5] = reload;
    scs[4] = 7;
}

__INLINE uintptr_t look::systick_t::get_jiffies() const
{
    return jiffies;
}

__INLINE uintptr_t look::systick_t::set_timer(timer_t& timer, uintptr_t interval)
{
    register auto _this asm ("a1") = this;
    register auto _timer asm ("a2") = &timer;
    register auto _interval asm ("a3") = interval;
    return LOOK_SVC(0, uintptr_t, &systick_t::do_set_timer, "0" (_this), "r" (_timer), "r" (_interval));
}

__INLINE uintptr_t look::systick_t::kill_timer(timer_t& timer)
{
    return set_timer(timer, 0);
}

__INLINE look::sync_t::sync_t()
{
    internal_data = 0;
}

__INLINE void look::sync_t::block(uintptr_t timeout)
{
    register auto _this asm ("a1") = this;
    register auto _timeout asm ("a2") = timeout;
    LOOK_SVC(1, uintptr_t, &sync_t::do_block, "0" (_this), "r" (_timeout));
}

__INLINE look::base::task_t* look::sync_t::wakeup(uintptr_t data, base::task_t* task)
{
    register auto _scheduler asm ("a1") = &scheduler;
    register auto _this asm ("a2") = this;
    register auto _task asm ("a3") = task;
    register auto _data asm ("a4") = data;
    return LOOK_SVC(0, base::task_t*, &sched_t::do_wakeup, "0" (_scheduler), "r" (_this), "r" (_task), "r" (_data));
}

__INLINE look::base::task_t* look::sync_t::do_wakeup(uintptr_t data, base::task_t* task)
{
    return scheduler.do_wakeup(*this, task, data);
}

__INLINE look::sem_t::sem_t(uintptr_t cnt)
{
    count = cnt;
}

__INLINE uintptr_t look::sem_t::get_count() const
{
    return count;
}

#ifdef __ARM_ARCH_6M__
__INLINE bool look::sem_t::trywait()
{
    register auto _this asm ("a1") = this;
    return LOOK_SVC(0, bool, &sem_t::do_trywait, "0" (_this));
}
#endif  // __ARM_ARCH_6M__

__INLINE bool look::sem_t::wait(uintptr_t timeout)
{
    register auto _this asm ("a1") = this;
    register auto _timeout asm ("a2") = timeout;
    return LOOK_SVC(1, bool, &sem_t::do_trywait, "0" (_this), "r" (_timeout));
}

__INLINE void look::sem_t::post()
{
    register auto _this asm ("a1") = this;
    LOOK_SVC(0, uintptr_t, &sem_t::do_post, "0" (_this));
}

__INLINE look::base::mbox_t::mbox_t(uint_fast8_t size)
{
    this->size = size;
    in = out = entries = 0;
}

__INLINE uint_fast8_t look::base::mbox_t::get_entries() const
{
    return entries;
}

__INLINE bool look::base::mbox_t::tryget(uintptr_t& msg)
{
    register auto _this asm ("a1") = this;
    register auto _msg asm ("a2") = &msg;
    return LOOK_SVC(0, bool, &base::mbox_t::do_tryget, "0" (_this), "r" (_msg));
}

__INLINE bool look::base::mbox_t::get(uintptr_t& msg, uintptr_t timeout)
{
    register auto _this asm ("a1") = this;
    register auto _msg asm ("a2") = &msg;
    register auto _timeout asm ("a3") = timeout;
    return LOOK_SVC(2, bool, &base::mbox_t::do_tryget, "0" (_this), "r" (_msg), "r" (_timeout));
}

__INLINE bool look::base::mbox_t::tryput(uintptr_t msg, bool front)
{
    register auto _this asm ("a1") = this;
    register auto _msg asm ("a2") = msg;
    register auto _front asm ("a3") = front;
    return LOOK_SVC(0, bool, &base::mbox_t::do_tryput, "0" (_this), "r" (_msg), "r" (_front));
}

__INLINE bool look::base::mbox_t::put(uintptr_t msg, bool front, uintptr_t timeout)
{
    register auto _this asm ("a1") = this;
    register auto _msg asm ("a2") = msg;
    register auto _front asm ("a3") = front;
    register auto _timeout asm ("a4") = timeout;
    return LOOK_SVC(3, bool, &base::mbox_t::do_tryput, "0" (_this), "r" (_msg), "r" (_front), "r" (_timeout));
}

template<typename QUEUE, typename MSG, uint8_t SIZE>
__INLINE look::queue_t<QUEUE, MSG, SIZE>::queue_t()
: QUEUE(SIZE)
{
}

template<typename QUEUE, typename MSG, uint8_t SIZE>
__INLINE uint_fast8_t look::queue_t<QUEUE, MSG, SIZE>::get_size() const
{
    return SIZE;
}

template<typename QUEUE, typename MSG, uint8_t SIZE>
__INLINE bool look::queue_t<QUEUE, MSG, SIZE>::peek(MSG& msg) const
{
    if (QUEUE::entries) {
        msg = buffer[QUEUE::out];
        return true;
    }
    return false;
}

template<typename QUEUE, typename MSG, uint8_t SIZE>
__INLINE bool look::queue_t<QUEUE, MSG, SIZE>::tryget(MSG& msg)
{
    return QUEUE::tryget(reinterpret_cast<uintptr_t&>(msg));
}

template<typename QUEUE, typename MSG, uint8_t SIZE>
__INLINE bool look::queue_t<QUEUE, MSG, SIZE>::get(MSG& msg, uintptr_t timeout)
{
    return QUEUE::get(reinterpret_cast<uintptr_t&>(msg), timeout);
}

template<typename QUEUE, typename MSG, uint8_t SIZE>
__INLINE bool look::queue_t<QUEUE, MSG, SIZE>::tryput(MSG msg)
{
    return QUEUE::tryput(uintptr_t(msg), false);
}

template<typename QUEUE, typename MSG, uint8_t SIZE>
__INLINE bool look::queue_t<QUEUE, MSG, SIZE>::tryput_front(MSG msg)
{
    return QUEUE::tryput(uintptr_t(msg), true);
}

template<typename QUEUE, typename MSG, uint8_t SIZE>
__INLINE bool look::queue_t<QUEUE, MSG, SIZE>::put(MSG msg, uintptr_t timeout)
{
    return QUEUE::put(uintptr_t(msg), false, timeout);
}

template<typename QUEUE, typename MSG, uint8_t SIZE>
__INLINE bool look::queue_t<QUEUE, MSG, SIZE>::put_front(MSG msg, uintptr_t timeout)
{
    return QUEUE::put(uintptr_t(msg), true, timeout);
}

template<typename QUEUE, typename MSG, uint8_t SIZE>
__INLINE bool look::queue_t<QUEUE, MSG, SIZE>::do_tryget(MSG& msg)
{
    return QUEUE::do_tryget(reinterpret_cast<uintptr_t&>(msg));
}

template<typename QUEUE, typename MSG, uint8_t SIZE>
__INLINE bool look::queue_t<QUEUE, MSG, SIZE>::do_tryput(MSG msg)
{
    return QUEUE::do_tryput(uintptr_t(msg), false);
}

template<typename QUEUE, typename MSG, uint8_t SIZE>
__INLINE bool look::queue_t<QUEUE, MSG, SIZE>::do_tryput_front(MSG msg)
{
    return QUEUE::do_tryput(uintptr_t(msg), true);
}

template<typename MSG, uint8_t SIZE>
__INLINE look::mbox_t<MSG, SIZE>::mbox_t()
: queue_t<base::mbox_t, MSG, SIZE>()
{
}

__INLINE look::base::flag_t::flag_t(uintptr_t flags)
{
    this->flags = flags;
}

__INLINE uintptr_t look::base::flag_t::peek() const
{
    return flags;
}

#ifdef __ARM_ARCH_6M__
__INLINE uintptr_t look::base::flag_t::poll(uintptr_t pattern, mode_t mode)
{
    register auto _this asm ("a1") = this;
    register auto _pattern asm ("a2") = pattern;
    register auto _mode asm ("a3") = mode;
    return LOOK_SVC(0, uintptr_t, &flag_t::do_poll, "0" (_this), "r" (_pattern), "r" (_mode));
}

__INLINE void look::base::flag_t::mask_bits(uintptr_t pattern)
{
    register auto _this asm ("a1") = this;
    register auto _pattern asm ("a2") = pattern;
    LOOK_SVC(0, uintptr_t, &flag_t::do_mask_bits, "0" (_this), "r" (_pattern));
}
#endif  // __ARM_ARCH_6M__

__INLINE uintptr_t look::base::flag_t::wait(uintptr_t pattern, mode_t mode, uintptr_t timeout)
{
    register auto _this asm ("a1") = this;
    register auto _pattern asm ("a2") = pattern;
    register auto _mode asm ("a3") = mode;
    register auto _timeout asm ("a4") = timeout;
    return LOOK_SVC(3, uintptr_t, &flag_t::do_poll, "0" (_this), "r" (_pattern), "r" (_mode), "r" (_timeout));
}

__INLINE look::link::flag_t::flag_t(uintptr_t flags)
: base::flag_t(flags)
{
}

__INLINE void look::link::flag_t::set_bits(uintptr_t pattern)
{
    register auto _this asm ("a1") = this;
    register auto _pattern asm ("a2") = pattern;
    LOOK_SVC(0, uintptr_t, &flag_t::do_set_bits, "0" (_this), "r" (_pattern));
}

__INLINE look::idle_task_t::idle_task_t()
{
}

__INLINE look::base::task_t::task_t()
{
}

__INLINE bool look::base::task_t::wakeup()
{
    register auto _this asm ("a1") = this;
    return LOOK_SVC(0, bool, &task_t::do_wakeup, "0" (_this));
}

__INLINE look::base::sched_t::sched_t()
{
    lock_count = 1;
    internal_data = 1;
}

__INLINE void look::base::sched_t::lock()
{
    uintptr_t cnt = lock_count;
    cnt++;
    lock_count = cnt;
}

__INLINE void look::base::sched_t::unlock()
{
    uintptr_t count = lock_count - 1;
    if (count != 0)
        lock_count = count;
    else
        unlock_reschedule();
}

__INLINE void look::base::sched_t::reschedule()
{
    register auto _this asm ("a1") = this;
    LOOK_SVC(0, uintptr_t, &sched_t::do_reschedule, "0" (_this));
}

__INLINE void look::base::sched_t::unlock_reschedule()
{
    register auto _this asm ("a1") = this;
    LOOK_SVC(0, uintptr_t, &sched_t::do_unlock_reschedule, "0" (_this));
}

__INLINE look::base::task_t& look::base::sched_t::get_current_task()
{
    return *cur_task;
}

__INLINE void look::delay(uintptr_t timeout)
{
    sync.block(timeout);
}

__INLINE look::link::task_t::task_t()
{
}

#ifdef __ARM_ARCH_7M__
__INLINE bool look::set_privilege(bool state)
{
    register bool _state asm ("a1") = state;
    return LOOK_SVC(0, bool, &do_set_privilege, "0" (_state));
}
#endif  // __ARM_ARCH_7M__

__INLINE uintptr_t look::get_version()
{
    return reinterpret_cast<uintptr_t>(&version);
}
#endif  // __LOOK_INLINE
#endif  // __LOOK_INTERFACE
#endif  // __LIGHTWEIGHT_OBJECT_ORENTED_KERNEL_HPP
